﻿using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace YaP.Library.YapControls
{
    internal enum ScrollBarDirection
    {
        SB_HORZ = 0,
        SB_VERT = 1,
        SB_CTL = 2,
        SB_BOTH = 3
    }

    internal enum ScrollInfoMask
    {
        SIF_RANGE = 0x1,
        SIF_PAGE = 0x2,
        SIF_POS = 0x4,
        SIF_DISABLENOSCROLL = 0x8,
        SIF_TRACKPOS = 0x10,
        SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
    }

    public class IrcRichTextBox : RichTextBox, IIRCTextBox
    {
        #region P/invoke

        private const int SB_BOTTOM = 7;
        private const uint WM_LBUTTONDOWN = 0x201;
        private const uint WM_LBUTTONUP = 0x202;
        private const int WM_VSCROLL = 0x0115;
        private const int EM_LINESCROLL = 0x00B6;

        [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
        protected static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "GetScrollInfo")]
        protected static extern IntPtr GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

        [DllImport("user32.dll", EntryPoint = "HideCaret")]
        public static extern long HideCaret(long hwnd);

        #endregion

        #region Desginer

        [Category("IRC Extended Properties"), Browsable(true)]
        public bool DispTime;
        [Category("IRC Extended Properties"), Browsable(true)]
        public bool MircColors;

        #endregion

        #region Private properties

        private readonly System.Windows.Forms.Timer tim;
        private StringBuilder exRtf;

        private bool SelectionInUse;

        #endregion

#if MS_NET
        //Should Be called only on MS Windows

#endif

        public IrcRichTextBox()
        {
            exRtf = new StringBuilder(RTF_HEADER + RTF_CRLF + RTF_EOD);
       
            HideCaret((long)Handle);
            GotFocus += IrcRichTextBox_GotFocus;
            Click += IrcRichTextBox_GotFocus;
            VScroll += new EventHandler(IrcRichTextBox_VScroll);
            SelectionChanged += new EventHandler(IrcRichTextBox_SelectionChanged);
            ReadOnly = true;
            tim = new System.Windows.Forms.Timer();
            tim.Tick += tim_Tick;
            tim.Interval = 1;
            tim.Start();
        }

        void IrcRichTextBox_SelectionChanged(object sender, EventArgs e)
        {
            this.SelectionInUse = SelectionLength > 0;
        }

        void IrcRichTextBox_VScroll(object sender, EventArgs e)
        {
            var sen = sender;
        }

        private void tim_Tick(object sender, EventArgs e)
        {
            SendMessage(Handle, WM_LBUTTONDOWN, new IntPtr(0), new IntPtr(0));
            SendMessage(Handle, WM_LBUTTONUP, new IntPtr(0), new IntPtr(0));

            tim.Stop();
        }


        private void IrcRichTextBox_GotFocus(object sender, EventArgs e)
        {
            HideCaret((long)Handle);
        }

        public bool ScrollIsAtEnd()
        {
            SCROLLINFO si = new SCROLLINFO();
            si.cbSize = (uint)Marshal.SizeOf(si);
            si.fMask = (uint)ScrollInfoMask.SIF_ALL;
            GetScrollInfo(Handle, (int)ScrollBarDirection.SB_VERT, ref si);
            return (si.nPos == si.nMax) || (si.nPos == 0);

        }

        public void SetCaretToEnd()
        {
            if (SelectionInUse) return;
            var ptrWparam = new IntPtr(SB_BOTTOM);
            var ptrLparam = new IntPtr(0);
            SendMessage(Handle, WM_VSCROLL, ptrWparam, ptrLparam);
        }

        public void AddRTF(object _in)
        {
            
            string _ircLine = (string)_in;
            StringBuilder ToMod = new StringBuilder(_ircLine);
            ToMod = ToMod.Replace("\\", "\\\\");
            ToMod = ToMod.Replace("}", "\\}");

            ToMod = ToMod.Append("\\b0\\highlight0\\cf17 ");

            //replacing irc color tag by RTF color tag
            while (ToMod.ToString().Contains(""))
            {
                //detecting ..
                int colorpos = ToMod.ToString().IndexOf("");
                bool complete = false;
                int i = colorpos + 1;
                int tp;
                string sBackColor = string.Empty;
                string sForeColor = string.Empty;
                int iBackColor;
                int iForeColor;
                int virgpos;
                int endpos;
                // a diry bugfix : When   character is detected, and there no message after this.
                complete = ((i + 1 >= ToMod.Length) || (i + 2 >= ToMod.Length) || (i + 3 >= ToMod.Length));
                while (!(complete))
                {
                    if ((IsNumeric(ToMod[i].ToString())) && (i <= colorpos + 2))
                    {
                        complete = false;
                        i++;
                    }
                    else
                    {
                        if (ToMod[i].ToString() == ",")
                        {
                            virgpos = i;
                            sForeColor = ToMod.ToString().Substring(colorpos + 1, virgpos - colorpos - 1);
                            i++;
                            while (IsNumeric(ToMod[i].ToString()))
                                i++;
                            endpos = i;

                            sBackColor = ToMod.ToString().Substring(virgpos + 1, endpos - virgpos - 1);
                            complete = true;
                        }
                        else
                        {
                            virgpos = i;
                            sForeColor = ToMod.ToString().Substring(colorpos + 1, virgpos - colorpos - 1);
                            complete = true;
                        }
                    }
                }
                Int32.TryParse(sForeColor, out iForeColor);
                if (sBackColor != string.Empty)
                {
                    Int32.TryParse(sBackColor, out iBackColor);
                    string OrigTag = "" + sForeColor + "," + sBackColor;
                    string NewTag = "\\f1\\highlight" + iBackColor + " \\cf" + iForeColor + " ";


                    ToMod.Replace(OrigTag, NewTag);
                }
                else
                {
                    string OrigTag = "" + sForeColor;
                    string NewTag = "\\cf" + iForeColor + " ";
                    ToMod.Replace(OrigTag, NewTag);
                }
                int smod = 1;
                while (ToMod.ToString().Contains(""))
                {
                    int sindex = ToMod.ToString().IndexOf("");
                    if ((smod % 2 == 0) && (smod > 0))
                        ToMod.Replace("", "\\b0 ", sindex, 1);
                    else
                        ToMod.Replace("", "\\b ", sindex, 1);
                    smod += 1;
                }
            }

            IrcRichAddRtfSync(ToMod);
        }

        #region Private Methods

        private async  Task IrcRichAddRtfSync(StringBuilder rtfStringBuilder)
        {
            StringBuilder ToMod = rtfStringBuilder;
            while ((exRtf.ToString().EndsWith(" ")) || (exRtf.ToString().EndsWith("\r")) ||
                   (exRtf.ToString().EndsWith("\n")))
                exRtf = exRtf.Remove(exRtf.Length - 1, 1);
            while (exRtf.ToString().EndsWith("}"))
                exRtf = exRtf.Remove(exRtf.Length - 1, 1);

            ToMod.Append(RTF_CRLF);
            ToMod.Append(RTF_EOD);

            exRtf.Append(ToMod.ToString());
            if (exRtf.Length > 32600)
            {
                exRtf = exRtf.Remove(0, 15000);
                exRtf.Insert(0, RTF_HEADER);
            }

            //SetCaretToEnd();
            base.Rtf = exRtf.ToString();
        }

        private bool IsNumeric(string s)
        {
            int i;
            return int.TryParse(s, out i);
        }

        #endregion

        #region "RTF_CONST"

        private const string RTF_CRLF = "\\par\r\n";
        private const string RTF_EOD = "}";

        private const string RTF_HEADER = "{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0\\fswiss\\fcharset0 Microsoft Arial;}}" +
                                          "{\\colortbl ;" +
            /* COLOR TABLE
* */
            //Black
                                          "\\red0\\green0\\blue0;" +
            // Blue
                                          "\\red22\\green26\\blue1101;" +
            //Green
                                          "\\red50\\green115\\blue32;" +
            //Red
                                          "\\red230\\green0\\blue0;" +
            //Maroon
                                          "\\red74\\green39\\blue11;" +
            //Purple
                                          "\\red99\\green21\\blue121;" +
            //Orange
                                          "\\red241\\green114\\blue27;" +
            //Yellow
                                          "\\red255\\green255\\blue0;" +
            //Light green
                                          "\\red70\\green237\\blue11;" +
            //Teal
                                          "\\red8\\green108\\blue97;" +
            //tu
                                          "\\red91\\green247\\blue253;" +
            //Dark blue
                                          "\\red13\\green23\\blue120;" +
            //Fuscia
                                          "\\red255\\green0\\blue210;" +
            //Dark grey
                                          "\\red96\\green96\\blue96;" +
            //light grey
                                          "\\red200\\green200\\blue200;" +
            // White is 16
                                          "\\red255\\green255\\blue255;" +
            // burly wood is 17
                                          "\\red206\\green175\\blue101;" +
                                          "}" +
                                          "\\viewkind4\\uc1\\pard\\cf17\\lang1036\\f0\\fs18\\par";

        #endregion

        #region Nested type: SyncAddRtfHandler

        private delegate void SyncAddRtfHandler(StringBuilder exRtf);

        #endregion
    }
}